home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / Talking Telnet / source / drag / drag.c next >
Text File  |  1996-06-22  |  11KB  |  392 lines

  1. /****************************************************************
  2. *    NCSA Telnet for the Macintosh                                *
  3. *                                                                *
  4. *    National Center for Supercomputing Applications                *
  5. *    Software Development Group                                    *
  6. *    152 Computing Applications Building                            *
  7. *    605 E. Springfield Ave.                                        *
  8. *    Champaign, IL  61820                                        *
  9. *                                                                *
  10. *    Copyright (c) 1986-1994,                                    *
  11. *    Board of Trustees of the University of Illinois                *
  12. ****************************************************************/
  13.  
  14. #include <Drag.h>
  15. #include <CodeFragments.h>
  16.  
  17. #include "wind.h"
  18.  
  19. #include "maclook.proto.h"        // For WindowPtr2WindRecPtr proto
  20. #include "rsinterf.proto.h"
  21. #include "parse.proto.h"
  22. #include "drag.proto.h"
  23.  
  24. #ifdef MPW
  25. #pragma segment RS
  26. #endif
  27.  
  28. Boolean    gHaveDragMgr, gDropcanAcceptItems, gDropcursorInContent, gDropDestCanAcceptItems;
  29.  
  30. #define    kScrollbarSize    15
  31.  
  32. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  33.                                   DragReference theDrag);
  34. PROTO_UPP(MyReceiveDropHandler, DragReceiveHandler);
  35. pascal OSErr MyTrackingHandler(short message, WindowPtr theWindow,
  36.                                void *handlerRefCon, DragReference theDrag);
  37. PROTO_UPP(MyTrackingHandler, DragTrackingHandler);
  38.  
  39. static    void LocalToGlobalRgn (RgnHandle rgn);
  40. static    void OutlineRegion (RgnHandle theRgn);
  41.  
  42. void    MyDragInit(void)
  43. {
  44.     OSErr    err;
  45.     long    dragMgrAttr;
  46.     
  47.     err = Gestalt(gestaltDragMgrAttr, &dragMgrAttr);
  48.     gHaveDragMgr = (err == noErr) && (dragMgrAttr & (1L << gestaltDragMgrPresent)) != 0;
  49.     #ifdef powerc
  50.     gHaveDragMgr = gHaveDragMgr && 
  51.         (dragMgrAttr & (1L << gestaltPPCDragLibPresent)) != 0
  52.         && ((long) InstallTrackingHandler) != kUnresolvedSymbolAddress;
  53.  
  54.  
  55.     #endif
  56.     // If the DragManager is available, install our tracking handlers
  57.     if (gHaveDragMgr) {
  58.         err = InstallTrackingHandler(MyTrackingHandlerUPP, nil, nil);
  59.  
  60.         if (err == noErr) {
  61.             // If all is ok so far, install the rcv handler
  62.             err = InstallReceiveHandler(MyReceiveDropHandlerUPP, nil, nil);
  63.             if (err != noErr) {
  64.                 // If an error ocurred installing the rcv handler, remove the tracking handler
  65.                 RemoveTrackingHandler(MyTrackingHandlerUPP, nil);
  66.                 }
  67.             }
  68.         
  69.         // If any error occurred, turn off DragManager support    
  70.         if (err != noErr) {
  71.             gHaveDragMgr = false;
  72.             }
  73.         }
  74. }
  75.  
  76. /*    MyReceiveDropHandler
  77.  *    Called by the Drag Manager when a drop occurs over one of Telnet's windows. */
  78. SIMPLE_UPP(MyReceiveDropHandler, DragReceiveHandler);
  79. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  80.                                   DragReference theDrag)
  81. {    
  82.     OSErr                result,memError;
  83.     Handle                dataH;
  84.     unsigned short        items, index;
  85.     ItemReference        theItem;
  86.     DragAttributes        attributes;
  87.     Size                textSize;
  88.     short                mouseDownModifiers, mouseUpModifiers;
  89.     WindRecPtr            tw;
  90.  
  91.     if (!gDropcanAcceptItems || !gDropcursorInContent)
  92.         return(dragNotAcceptedErr);
  93.  
  94.     SetPort(theWindow);
  95.  
  96.     // No text yet
  97.     dataH = nil;
  98.     
  99.     GetDragAttributes(theDrag, &attributes);
  100.     GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  101.  
  102.     //    Loop through all of the drag items contained in this drag and collect the text
  103.     //    into the accumulation handle.
  104.  
  105.     CountDragItems(theDrag, &items);
  106.  
  107.     for (index = 1; index <= items; index++) {
  108.         //    Get the item's reference number, so we can refer to it.
  109.         GetDragItemReferenceNumber(theDrag, index, &theItem);
  110.  
  111.         //    Try to get the flags for a 'TEXT' flavor. If this returns noErr,
  112.         //    then we know that a 'TEXT' flavor exists in the item.
  113.         result = GetFlavorDataSize(theDrag, theItem, 'TEXT', &textSize);
  114.  
  115.         if (result == noErr) {
  116.             if (dataH == nil) {                    // No data yet, create a new handle for accumulation
  117.                 dataH = myNewHandle(textSize);
  118.                 if (dataH == nil) {
  119.                     return memFullErr;            // Exit if there is an error
  120.                     }
  121.                 }
  122.             else {                                // Append to existing TEXT data
  123.                 memError = mySetHandleSize(dataH, GetHandleSize(dataH) + textSize);    // Grow the handle
  124.                 if (memError != noErr) {
  125.                     return memFullErr;            // Exit if there is a problem
  126.                     }
  127.                 }
  128.                 
  129.  
  130.             // Temporarily lock down the accumlation handle
  131.             HLock(dataH);
  132.         
  133.             // Get the drag data    
  134.             GetFlavorData(theDrag, theItem, 'TEXT', *dataH, &textSize, 0L);
  135.  
  136.             // Ok to unlock the accumulation handle
  137.             HUnlock(dataH);
  138.             }
  139.         }
  140.  
  141.     // Get the length of all that was accumulated
  142.     textSize = GetHandleSize(dataH);
  143.  
  144.     //    If we actually received text, insert it into the destination.
  145.     if (textSize != 0) {
  146.         if (attributes & dragHasLeftSenderWindow) {
  147.             HideDragHilite(theDrag);
  148.             }
  149.  
  150.         HLock(dataH);
  151.  
  152.         // Send the text to the window.        
  153.         tw = WindowPtr2WindRecPtr(theWindow);
  154.         if (tw != nil) {
  155.             SendStringAsIfTyped(tw, *dataH, textSize);
  156.             }
  157.         HUnlock(dataH);
  158.         }
  159.  
  160.     if (dataH != nil) {
  161.         DisposeHandle(dataH);
  162.         }
  163.  
  164.     return(noErr);
  165. }
  166.  
  167. /*    MyTrackingHandler
  168.  *    This is the drag tracking handler for windows in the DragText application.*/
  169. SIMPLE_UPP(MyTrackingHandler, DragTrackingHandler);
  170. pascal OSErr MyTrackingHandler(short message, WindowPtr theWindow,
  171.                                void *handlerRefCon, DragReference theDrag)
  172. {
  173.     short                result;
  174.     unsigned short        count, index;
  175.     unsigned long        flavorFlags, attributes;
  176.     ItemReference        theItem;
  177.     RgnHandle            theRgn, selectionRgn;
  178.     Point                theMouse, localMouse;
  179.     Rect                dragRect;
  180.     GrafPtr                savePort;
  181.     Boolean                inOriginalSelection;
  182.     
  183.     if ((message != dragTrackingEnterHandler) && (!gDropcanAcceptItems))
  184.         return(noErr);
  185.  
  186.     if ((message != dragTrackingEnterHandler) && (message != dragTrackingEnterWindow) 
  187.             && (!gDropDestCanAcceptItems))
  188.         return(noErr);
  189.  
  190.     GetDragAttributes(theDrag, &attributes);
  191.  
  192.     switch (message) {
  193.  
  194.         case dragTrackingEnterHandler:
  195.             //    We get called with this message the first time that a drag enters ANY
  196.             //    window in our application. 
  197.             gDropcanAcceptItems = true;
  198.                                         
  199.             //    Check to see if all of the drag items contain
  200.             //    TEXT. We only accept a drag if all of the items in the drag can be accepted.
  201.             CountDragItems(theDrag, &count);
  202.  
  203.             for (index = 1; index <= count; index++) {
  204.                 GetDragItemReferenceNumber(theDrag, index, &theItem);
  205.  
  206.                 result = GetFlavorFlags(theDrag, theItem, 'TEXT', &flavorFlags);
  207.  
  208.                 if (result != noErr) {
  209.                     gDropcanAcceptItems = false;
  210.                     break;
  211.                     }
  212.                 }
  213.             break;
  214.  
  215.         case dragTrackingEnterWindow:
  216.             //    We receive an EnterWindow message each time a drag enters one of our
  217.             //    application's windows. We initialize our global variables for tracking
  218.             //    the drag through the window.
  219.  
  220.             // Assume this window can accept the drag
  221.             gDropDestCanAcceptItems = true;
  222.             
  223.             // If it is not a connection window, it cannot accept a drop.
  224.             if (((WindowPeek)theWindow)->windowKind != WIN_CNXN) {
  225.                 gDropDestCanAcceptItems = false;
  226.                 break;
  227.                 }
  228.             
  229.             // Initially no blue box.
  230.             gDropcursorInContent = false;
  231.             break;
  232.  
  233.         case dragTrackingInWindow:
  234.             GetPort(&savePort);
  235.             SetPort(theWindow);
  236.  
  237.             //    We receive InWindow messages as long as the mouse is in one of our windows
  238.             //    during a drag. We draw the window highlighting when we get these messages.
  239.             GetDragMouse(theDrag, &theMouse, 0L);
  240.  
  241.             //    If we are still in the sender window, check to see if we should draw a blue box.
  242.             //    inOriginalSelection is true if the mouse is still within the confines of the
  243.             //    selected text's original location.  This allows the user to cancel a drop by
  244.             //    dropping the text somewhere inside of the original selection.
  245.             if (attributes & dragInsideSenderWindow) {
  246.                 localMouse = theMouse;
  247.                 GlobalToLocal(&localMouse);
  248.                 
  249.                 selectionRgn = RSGetTextSelRgn(WindowPtr2WindRecPtr(theWindow)->vs);
  250.                 inOriginalSelection = PtInRgn(localMouse, selectionRgn);
  251.                 DisposeRgn(selectionRgn);
  252.                 }
  253.             else {
  254.                 inOriginalSelection = false;
  255.                 }
  256.  
  257.             //    Show or hide the window highlighting when the mouse enters or leaves the
  258.             //    text area in our window (we don't want to show the highlighting when
  259.             //    the mouse is over the scroll bars).
  260.             dragRect = (*(((WindowPeek)theWindow)->contRgn))->rgnBBox;
  261.             
  262.             //    Subtract out the scrollbars.
  263.             dragRect.right -= kScrollbarSize;
  264.             dragRect.bottom -= kScrollbarSize;
  265.             
  266.             //    If the mouse is in the text area and not in the original selection,
  267.             //    draw the blue box.            
  268.             if (PtInRect(theMouse, &dragRect) && !inOriginalSelection) {
  269.                 if (!gDropcursorInContent) {
  270.  
  271.                     // Set up the blue box region.
  272.                     GlobalToLocal(&topLeft(dragRect));
  273.                     GlobalToLocal(&botRight(dragRect));
  274.                     RectRgn(theRgn = NewRgn(), &dragRect);
  275.  
  276.                     ShowDragHilite(theDrag, theRgn, true);
  277.  
  278.                     DisposeRgn(theRgn);
  279.                     }
  280.                     
  281.                 // Remember that we are in a valid drop location.
  282.                 gDropcursorInContent = true;
  283.  
  284.                 }
  285.             else {
  286.                 // We have moved out of a valid drop region.
  287.  
  288.                 if (gDropcursorInContent) {            // Hide the box if it was drawn.
  289.                     HideDragHilite(theDrag);
  290.                     }
  291.                     
  292.                 // Remember that we are outside of a valid drop region.
  293.                 gDropcursorInContent = false;
  294.  
  295.                 }    
  296.  
  297.             SetPort(savePort);
  298.             break;
  299.  
  300.         case dragTrackingLeaveWindow:
  301.                 HideDragHilite(theDrag);
  302.             break;
  303.  
  304.         case dragTrackingLeaveHandler:
  305.             break;
  306.  
  307.     }
  308.  
  309.     return(noErr);
  310. }
  311.  
  312. OSErr DragText(EventRecord *ev, Point where, short w, Boolean *dragged)
  313. {
  314.     DragReference    dragRef;
  315.     OSErr            err = noErr;
  316.     Boolean            haveDragRef = false;
  317.     RgnHandle        dragRgn = nil;
  318.     Handle            textH = nil;
  319.     long            size;
  320.     
  321.     *dragged = false;
  322.     if (!gHaveDragMgr) {
  323.         return noErr;
  324.         }
  325.         
  326.     dragRgn = RSGetTextSelRgn(w);
  327.     if (dragRgn == nil) {
  328.         return noErr;
  329.         }
  330.     if (!PtInRgn(where, dragRgn)) {
  331.         DisposeRgn(dragRgn);
  332.         return noErr;
  333.         }
  334.     if (!WaitMouseMoved(ev->where)) return noErr;
  335.     *dragged = true;
  336.  
  337.     textH = RSGetTextSel(w, 0);
  338.     
  339.     if ((textH == (char **)-1L) || (textH == nil)) {
  340.         textH = nil;
  341.         goto exit;
  342.         }
  343.     
  344.     HLock(textH);
  345.     size = GetHandleSize(textH);
  346.     
  347.     err = NewDrag(&dragRef);
  348.     if (err != noErr) goto exit;
  349.     haveDragRef = true;
  350.  
  351.     err = AddDragItemFlavor(dragRef, 1, 'TEXT', *textH, size, 0);
  352.     if (err != noErr) goto exit;
  353.  
  354.     LocalToGlobalRgn(dragRgn);
  355.     OutlineRegion(dragRgn);
  356.  
  357.     err = TrackDrag(dragRef, ev, dragRgn);
  358.     if (err != noErr && err != userCanceledErr) goto exit;
  359.  
  360.     DisposeRgn(dragRgn);
  361.     DisposeDrag(dragRef);
  362.     DisposeHandle(textH);
  363.     return noErr;
  364.     
  365. exit:
  366.  
  367.     if (haveDragRef) DisposeDrag(dragRef);
  368.     if (dragRgn != nil) DisposeRgn(dragRgn);
  369.     if (textH != nil) DisposeHandle(textH);
  370.     return err;
  371. }
  372.  
  373. static    void LocalToGlobalRgn (RgnHandle rgn)
  374. {
  375.     Point where;
  376.     
  377.     SetPt(&where, 0, 0);
  378.     LocalToGlobal(&where);
  379.     OffsetRgn(rgn, where.h, where.v);
  380. }
  381.  
  382. static    void OutlineRegion (RgnHandle theRgn)
  383. {
  384.     RgnHandle tempRgn;
  385.     
  386.     tempRgn = NewRgn();
  387.     CopyRgn(theRgn, tempRgn);
  388.     InsetRgn(tempRgn, 1, 1);
  389.     DiffRgn(theRgn, tempRgn, theRgn);
  390.     DisposeRgn(tempRgn);
  391. }
  392.